﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Criterion;

namespace SimpleServiceBus.Persistence.NHibernate.Repositories
{
    public class Repository<T> : IRepository<T> where T:class
    {
        private readonly ISessionManager _sessionManager;

        public Repository(ISessionManager sessionManager)
        {
            if (sessionManager == null)
                throw new ArgumentNullException("sessionManager");

            _sessionManager = sessionManager;
        }

        public Repository():this(DataSessionManager.Current)
        {
        }

        protected ISession Session { get { return _sessionManager.CurrentSession; } }

        public virtual T SaveOrUpdate(T entity)
        {
            Session.SaveOrUpdate(entity);
            return entity;
        }

        public virtual T Get(int id)
        {
            return Session.Get<T>(id);
        }

        public virtual void Delete(T entity)
        {
            Session.Delete(entity);
        }

        public virtual T FindOne(params ICriterion[] queryCritiera)
        {
            IList<T> found = FindAll(queryCritiera);
            if (found.Count > 1)
                throw new Exception("Query returned more than one value");
            if (found.Count > 0)
                return found[0];
            return null;
        }

        public virtual IList<T> FindAll(params ICriterion[] queryCriteria)
        {
            ICriteria criteria = CreateCriteria(queryCriteria); 
            return criteria.List<T>();
        }

        public virtual IList<T> FindTopN(int topCount,string orderBy,bool ascending,params ICriterion[] queryCriteria)
        {
            return CreateCriteria(queryCriteria)
                      .AddOrder(new Order(orderBy,ascending))
                      .SetMaxResults(topCount).List<T>();
            
        }

        protected ICriteria CreateCriteria(ICriterion[] queryCriteria)
        {
            ICriteria criteria = Session.CreateCriteria(typeof(T));
            if (queryCriteria != null && queryCriteria.Length > 0)
            {
                foreach (var criterion in queryCriteria)
                    criteria.Add(criterion);
            }
            return criteria;
        }
    }
}
